﻿using System;
using System.Collections.Generic;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Ioc;

namespace MugenMvvmToolkitTest.TestInfrastructure
{
    public delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);

    public class TestIocAdapter : IIocAdapter
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="TestIocAdapter"/> class.
        /// </summary>
        public TestIocAdapter(TestIocAdapter testIocAdapter = null)
        {
            Parent = testIocAdapter;
            Container = this;
            if (testIocAdapter == null) return;
            GetFunc = testIocAdapter.GetFunc;
            BindToConstantFunc = testIocAdapter.BindToConstantFunc;
            BindFunc = testIocAdapter.BindFunc;
            UnbindFunc = testIocAdapter.UnbindFunc;
        }

        #endregion

        #region Properties

        public bool IsDisposed { get; set; }

        public Func<Type, bool> CanResolveDelegate { get; set; }

        public Func<Type, string, IIocParameter[], object> GetFunc { get; set; }

        public Func<Type, string, IIocParameter[], object[]> GetAllFunc { get; set; }

        public Action<Type, object, string> BindToConstantFunc { get; set; }

        public Action<Type, Type, DependencyLifecycle, string> BindFunc { get; set; }

        public Action<Type> UnbindFunc { get; set; }

        #endregion

        #region Implementation of IDisposable

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        void IDisposable.Dispose()
        {
            IsDisposed = true;
        }

        #endregion

        #region Implementation of IIocAdapter

        /// <summary>
        /// Gets the id of <see cref="IIocAdapter"/>.
        /// </summary>
        int IIocAdapter.Id
        {
            get
            {
                return 0;
            }
        }

        /// <summary>
        ///     Gets the parent ioc adapter.
        /// </summary>
        public IIocAdapter Parent { get; private set; }

        /// <summary>
        ///     Gets the original ioc container.
        /// </summary>
        public object Container { get; private set; }

        /// <summary>
        ///     Creates a child ioc adapter.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IIocAdapter" />.
        /// </returns>
        IIocAdapter IIocAdapter.CreateChild()
        {
            return new TestIocAdapter(this)
            {
                GetFunc = GetFunc,
                BindFunc = BindFunc,
                CanResolveDelegate = CanResolveDelegate,
                BindToConstantFunc = BindToConstantFunc,
                GetAllFunc = GetAllFunc,
                UnbindFunc = UnbindFunc
            };
        }

        /// <summary>
        ///     Gets an instance of the specified service.
        /// </summary>
        /// <param name="service">The specified service type.</param>
        /// <param name="name">The specified binding name.</param>
        /// <param name="parameters">The specified parameters.</param>
        /// <returns>An instance of the service.</returns>
        object IIocAdapter.Get(Type service, string name, params IIocParameter[] parameters)
        {
            return GetFunc(service, name, parameters);
        }

        /// <summary>
        ///     Gets all instances of the specified service.
        /// </summary>
        /// <param name="service">Specified service type.</param>
        /// <param name="name">The specified binding name.</param>
        /// <param name="parameters">The specified parameters.</param>
        /// <returns>An instance of the service.</returns>
        IEnumerable<object> IIocAdapter.GetAll(Type service, string name, params IIocParameter[] parameters)
        {
            return GetAllFunc(service, name, parameters);
        }

        /// <summary>
        ///     Indicates that the service should be bound to the specified constant value.
        /// </summary>
        void IIocAdapter.BindToConstant(Type service, object constValue, string name)
        {
            BindToConstantFunc(service, constValue, name);
        }

        /// <summary>
        ///     Indicates that the service should be bound to the specified type.
        /// </summary>
        /// <param name="service">The specified service type.</param>
        /// <param name="typeTo">The specified to type</param>
        /// <param name="name">The specified binding name.</param>
        /// <param name="dependencyLifecycle">
        ///     The specified <see cref="DependencyLifecycle" />
        /// </param>
        void IIocAdapter.Bind(Type service, Type typeTo, DependencyLifecycle dependencyLifecycle, string name)
        {
            BindFunc(service, typeTo, dependencyLifecycle, name);
        }

        /// <summary>
        ///     Unregisters all bindings with specified conditions for the specified service.
        /// </summary>
        /// <param name="service">The specified service type.</param>
        void IIocAdapter.Unbind(Type service)
        {
            UnbindFunc(service);
        }

        /// <summary>
        /// Determines whether the specified request can be resolved.
        /// </summary>
        /// <param name="service">The specified service type.</param>
        /// <returns>
        /// <c>True</c> if the specified service has been resolved; otherwise, <c>false</c>.
        /// </returns>
        bool IIocAdapter.CanResolve(Type service)
        {
            if (CanResolveDelegate == null)
                return false;
            return CanResolveDelegate(service);
        }

        #endregion

        #region Implementation of IServiceProvider

        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <returns>
        /// A service object of type <paramref name="serviceType"/>.
        ///                     -or- 
        ///                 null if there is no service object of type <paramref name="serviceType"/>.
        /// </returns>
        /// <param name="serviceType">An object that specifies the type of service object to get. 
        ///                 </param>
        object IServiceProvider.GetService(Type serviceType)
        {
            return ((IIocAdapter)this).Get(serviceType);
        }

        #endregion
    }
}
